////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//         This file is distributed under the BSD 2-Clause open source license. See Licenses/License.txt for details.         //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#ifndef __WN_SCRIPTING_TYPE_ELEMENT_H__
#define __WN_SCRIPTING_TYPE_ELEMENT_H__

#include "WNCore/inc/WNTypes.h"
#include "WNStrings/inc/WNStrings.h"
#include "WNMemory/inc/WNManipulation.h"
#include <vector>

namespace llvm {
    class Type;
    class StructType;
};

namespace WNScripting {
    enum WNTypeType {
        eWNNormalType,
        eWNStructType,
        eWNArrayType
    };

    struct WNScriptTypeInternal;

    struct WNContainedStructType {
        WN_CHAR* mName;
        WNScriptTypeInternal* mType;
    };

    struct WNScriptTypeInternal {
        WN_CHAR* mName;
        WN_FLOAT32 mPriority;
        WNScriptTypeInternal* mArrayType;
        WNScriptTypeInternal* mArrayParent;
        std::vector<WNContainedStructType> mStructTypes;
        WN_SIZE_T mAlignment;
        WN_CHAR mTag[4];
        llvm::Type* mLLVMType;
        llvm::StructType* mLLVMStructType;
        WN_BOOL mFinalizedStruct;

        WNScriptTypeInternal(const WN_CHAR* _name, WN_INT32 _alignment, WN_FLOAT32 _priority, llvm::Type* _type,const WN_CHAR* _tag) :
            mAlignment(_alignment),
            mPriority(_priority),
            mLLVMType(_type),
            mLLVMStructType(0),
            mArrayType(0),
            mArrayParent(0),
            mFinalizedStruct(WN_FALSE) {
            mName = WNStrings::WNStrNDup(_name, 256);
            WNMemory::WNMemCpy(mTag, _tag, 4*sizeof(WN_CHAR));
        }
        WNScriptTypeInternal(const WN_CHAR* _name, WN_INT32 _alignment, WN_FLOAT32 _priority, llvm::Type* _type, llvm::StructType* _sType, const WN_CHAR* _tag) :
            mAlignment(_alignment),
            mPriority(_priority),
            mLLVMStructType(_sType),
            mLLVMType(_type),
            mArrayType(0),
            mArrayParent(0),
            mFinalizedStruct(WN_FALSE) {
            mName = WNStrings::WNStrNDup(_name, 256);
            WNMemory::WNMemCpy(mTag, _tag, 4*sizeof(WN_CHAR));
        }
        WNScriptTypeInternal(WNScriptTypeInternal* _containedType, llvm::Type* _llvmType, WN_FLOAT32 _priority, const WN_CHAR* _tag) :
            mArrayType(_containedType),
            mName(WN_NULL),
            mAlignment(_containedType->mAlignment),
            mPriority(_priority),
            mLLVMType(_llvmType),
            mLLVMStructType(0),
            mArrayParent(0),
            mFinalizedStruct(WN_FALSE) {
            _containedType->mArrayParent = this;
            WNMemory::WNMemCpy(mTag, _tag, 4*sizeof(WN_CHAR));
            WN_SIZE_T mNameSize = WNStrings::WNStrLen(_containedType->mName);
            mName = WNMemory::WNMallocT<WN_CHAR>(mNameSize + 1 /*NULL*/ + 2 /*"[]"*/);
            memcpy(mName, _containedType->mName, mNameSize);
            mName[mNameSize] = '[';
            mName[mNameSize+1] = ']';
            mName[mNameSize+2] = '\0';
        }
    };
    typedef WNScriptTypeInternal* WNScriptType;
}
#endif // __WN_SCRIPTING_TYPE_ELEMENT_H__
